// 表明协议字段
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <algorithm>

#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/wait.h>

#include "Util.hpp"
#include "Log.hpp"

#define Sep ": "
#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define LINE_END "\r\n"
#define PAGE_400 "400.html"
#define PAGE_404 "404.html"
#define PAGE_500 "500.html"

// 状态码
#define OK 200
#define BAD_REQUEST 400
#define NOT_FOUND 404
#define SERVER_ERROR 500

static std::string Code2Desc(int code)
{
    std::string desc;
    switch (code)
    {
    case 200:
        desc = "OK";
        break;
    case 404:
        desc = "Not Found";
        break;
    default:
        break;
    }
    return desc;
}

static std::string Suffix2Desc(const std::string &suffix)
{
    static std::unordered_map<std::string, std::string> suffix2desc = {
        {".html", "text/html"},
        {".js", "application/javascript"},
        {".jpg", "application/x-jpg"},
        {".css", "text/css"},
        {".xml", "application/xml"}};
    auto iter = suffix2desc.find(suffix);
    if (iter != suffix2desc.end())
    {
        // 找到了
        return iter->second;
    }
    return "text/html";
}

class HttpRequest
{
public:
    std::string request_line;                // 请求行
    std::vector<std::string> request_header; // 请求报头
    std::string blank;                       // 空行
    std::string request_body;                // 请求正文

    // 解析完毕之后的结果
    std::string method;
    std::string uri;
    std::string version;

    std::unordered_map<std::string, std::string> header_kv;
    int Content_Length; // 报文中的属性（描述正文的大小字节）
    std::string path;
    std::string query_string;
    std::string suffix; // 后缀
    size_t size;

    bool cgi; // 可执行程序（CGI机制）
public:
    HttpRequest() : Content_Length(0), cgi(false)
    {
    }
    ~HttpRequest()
    {
    }
};

class HttpResponse
{
public:
    std::string status_line;                  // 响应状态行
    std::vector<std::string> response_header; // 响应报头
    std::string blank;                        // 空行
    std::string response_body;                // 响应正文（响应体）

    // 响应信息
    int status_code; // 状态码
    int fd;
    int size; // 大小
public:
    HttpResponse() : status_code(OK), blank(LINE_END), fd(-1)
    {
    }
    ~HttpResponse()
    {
    }
};

// 读取请求 -> 分析请求 -> 构建响应
class EndPoint
{
private:
    int sock;
    HttpRequest http_request;
    HttpResponse http_response;
    bool stop;

private:
    // 读取请求行
    bool RecvHttpRequestLine()
    {
        // Util::ReadLine(sock, http_request.request_line);
        // LOG(Info, http_request.request_line);

        auto &line = http_request.request_line;
        if(Util::ReadLine(sock, line) > 0)
        {
            line.resize(line.size()-1);
            LOG(Info, http_request.request_line);
        } 
        else{
            stop = true;
        } 
        return stop;
    }
    // 读取请求报头
    bool RecvHttpRequestHeader()
    {
        std::string line;
        while (true)
        {
            line.clear();
            // Util::ReadLine(sock, line);
            if(Util::ReadLine(sock, line) <= 0)
            {
                stop = true;
                break;
            }
            if (line == "\n")
            {
                http_request.blank = line;
                break;
            }
            line.resize(line.size() - 1);
            http_request.request_header.push_back(line);
            LOG(Info, line);
        }
        return stop;
    }
    // 解析请求行
    void ParseHttpRequestLine()
    {
        auto &line = http_request.request_line;
        std::stringstream ss(line);
        ss >> http_request.method >> http_request.uri >> http_request.version;

        // LOG(Info, http_request.method);
        // LOG(Info, http_request.uri);
        // LOG(Info, http_request.version);

        // 将请求信息（post, get, ...）转化为大写
        auto &method = http_request.method;
        std::transform(method.begin(), method.end(), method.begin(), ::toupper);
    }
    // 解析请求报头
    void ParseHttpRequestHeader()
    {
        std::string key;
        std::string value;
        for (auto &line : http_request.request_header)
        {
            if (Util::CutString(line, key, value, Sep))
            {
                http_request.header_kv.insert({key, value});
            }
        }
    }
    // 判断是否需要读取正文
    bool IsNeedRecvHttpRequestBody()
    {
        auto &method = http_request.method;
        if (method == "POST")
        {
            auto &header_kv = http_request.header_kv;
            auto iter = header_kv.find("Content-Length");
            if (iter != header_kv.end())
            {
                http_request.Content_Length = atoi(iter->second.c_str());
                return true;
            }
        }
        return false;
    }
    // 读取请求正文
    bool RecvHttpRequestBody()
    {
        if (IsNeedRecvHttpRequestBody())
        {
            int content_length = http_request.Content_Length;
            auto &body = http_request.request_body;
            char ch = 0;
            while (content_length)
            {
                ssize_t s = recv(sock, &ch, 1, 0);
                if (s > 0)
                {
                    body.push_back(ch);
                    content_length--;
                }
                else
                {
                    stop = true;
                    break;
                }
            }
            LOG(Info, body);
        }
        return stop;
    }

    // CGI机制
    int ProcessCgi()
    {
        int code = OK;
        // 父进程数据
        auto &method = http_request.method;
        auto &query_string = http_request.query_string; // GET
        auto &body_text = http_request.request_body;    // POST
        auto &bin = http_request.path;                  // 要让子进程执行的目标程序，一定存在
        auto &content_length = http_request.Content_Length;
        auto &response_body = http_response.response_body;  // 响应正文段

        // 给子进程构建 环境变量
        std::string query_string_env;
        std::string method_env;
        std::string content_length_env;

        // 站在 父进程的角度（读写管道/两个）
        int input[2];  // 父进程用来读
        int output[2]; // 父进程用来写
        // 创建两个匿名管道
        if (pipe(input) < 0)
        {
            LOG(ERROR, "pipe inout error");
            code = 404;
            return code;
        }
        if (pipe(output) < 0)
        {
            LOG(ERROR, "pipe output error");
            code = 404;
            return code;
        }

        // 因为是新线程，但是从头到尾都只有一个进程，就是 httpserver
        pid_t pid = fork();
        if (pid == 0)
        { // child
            close(input[0]);
            close(output[1]);

            // 构建环境变量
            // Method 环境变量
            method_env = "METHOD=";
            method_env += method;
            // cs
            std::cout << "cgi: " << method_env << std::endl;
            std::cout << "bin: " << bin << std::endl;
            putenv((char *)method_env.c_str());

            // 若是Get
            if (method == "GET")
            {
                query_string_env = "QUERY_STRING=";
                query_string_env += query_string; // x=100&y=200
                putenv((char *)query_string_env.c_str());
                LOG(Warning, "Get Method Add Query_string Env");
            }
            else if(method == "POST")
            {
                content_length_env = "CONTENT_LENGTH=";
                content_length_env += std::to_string(content_length);
                putenv((char*)content_length_env.c_str());
                LOG(Info, "POST Method, Add Content-Length Env");
            }

            // 站在子进程角度
            // input[1] -> 写入 1号文件描述符
            // output[0]-> 读取 0号文件描述符
            dup2(input[1], 1);
            dup2(output[0], 0);

            // exec*进程替换系列
            execl(bin.c_str(), bin.c_str(), nullptr);
            exit(1);
        }
        else if (pid < 0)
        { // error
            LOG(ERROR, "fork error");
            return 404;
        }
        else
        { // parent
            close(input[1]);
            close(output[0]);

            // 父进程判断method 标识符是什么（Get/ POst）
            if (method == "POST") // 如果是POST机制，就将正文上的数据交给子进程，让子进程去处理
            {
                const char *start = body_text.c_str();
                int total = 0;
                int size = 0;
                while ((total < content_length) && (size = write(output[1], start + total, body_text.size() - total)) > 0)
                {
                    total += size;
                }
            }
            // 父进程对其做出响应
            char ch = 0;
            while(read(input[0], &ch, 1) > 0){
                response_body.push_back(ch);
            }
 
            // 父进程等待子进程（进程等待）
            int status = 0;
            pid_t rid = waitpid(pid, &status, 0);
            if(rid == pid)
            {
                if(WIFEXITED(status)){
                    if(WEXITSTATUS(status) == 0){
                        code = OK;
                    }
                    else{
                        code = BAD_REQUEST;
                    }
                }
                else{
                    code = SERVER_ERROR;
                }
            }

            close(input[0]);
            close(output[1]);
        }
        // CGI执行完之后的结果，并不可以直接返回给浏览番，因为这部分内容只是响应的正文！
        return code;    
    }

    // （404 差错处理）(错误处理)
    void HandlerError(std::string page)
    {
        http_request.cgi = false;

        // 需要给用户返回对应的404网页页面
        http_response.fd = open(page.c_str(), O_RDONLY);
        if(http_response.fd > 0){
            struct stat st;
            stat(page.c_str(), &st);
            http_request.size = st.st_size;

            std::string line = "Content-Type: text/html";
            line += LINE_END;
            http_response.response_header.push_back(line);
            
            line = "Content-Length: ";
            line += std::to_string(st.st_size);
            line += LINE_END;
            http_response.response_header.push_back(line);
        }
    }

    // 返回静态网页
    // int ProcessNonCgi(int size)
    int ProcessNonCgi()
    {
        http_response.fd = open(http_request.path.c_str(), O_RDONLY);
        if (http_response.fd >= 0)
        {
            // http_response.status_line = HTTP_VERSION;
            // http_response.status_line += " ";
            // http_response.status_line += std::to_string(http_response.status_code);
            // http_response.status_line += " ";
            // http_response.status_line += Code2Desc(http_response.status_code); // 状态码描述
            // http_response.status_line += LINE_END;
            // // http_response.size = size;

            // std::string header_line = "Content-Length: ";
            // header_line += std::to_string(http_request.size);
            // header_line += LINE_END;
            // http_response.response_header.push_back(header_line);

            // header_line = "Content-Type: ";
            // header_line += Suffix2Desc(http_request.suffix);
            // header_line += LINE_END;
            // http_response.response_header.push_back(header_line);

            LOG(Info, " open 静态网页 success!");
            return OK;
        }
        return NOT_FOUND;
    }

    void HandlerOKFound()
    {
        std::string line = "Content-Type: ";
        line += Suffix2Desc(http_request.suffix);
        line += LINE_END;
        http_response.response_header.push_back(line);
        
        line = "Content-Length: ";
        if(http_request.cgi){
            // 执行CGI机制
            line += std::to_string(http_response.response_body.size());
        }
        else{
            line += std::to_string(http_request.size);    // GET
        }
        line += LINE_END;
        http_response.response_header.push_back(line);
    }

    // 差错处理
    // bool BuildHttpResponseHelper(int code)
    bool BuildHttpResponseHelper()
    {
        auto &code = http_response.status_code;     // 直接响应中的status_code状态码

        // 有错误了，就
        // http_request
        // http_response
        auto& status_line = http_response.status_line;
        status_line += HTTP_VERSION;
        status_line += " ";
        status_line += std::to_string(code);
        status_line += " ";
        status_line += Code2Desc(code);
        status_line += LINE_END;

        // 构建响应正文，可能包括响应报头
        std::string path = WEB_ROOT;
        path += "/";
        switch (code)
        {
        case 200:
            HandlerOKFound();
            break;
        case 400:
            path += PAGE_400;
            HandlerError(path);  // 都先统一做400处理
            break;
        case 404:
            path += PAGE_404;
            HandlerError(path);
            break;
        case 500:
            path += PAGE_500;
            HandlerError(path);
            break;
        default:
            break;
        }
    }

public:
    EndPoint(int _sock) : sock(_sock),stop(false)
    {
    }

    // // 读取请求
    // void RecvHttpRequest()
    // {
    //     RecvHttpRequestLine();
    //     RecvHttpRequestHeader();
    // }
    // // 解析请求
    // void ParseHttpRequest()
    // {
    //     ParseHttpRequestLine();
    //     ParseHttpRequestHeader();
    //     RecvHttpRequestBody();
    // }

    bool IsStop()
    {
        return stop;
    }
    // 简化为 => 读取请求
    void RecvHttpRequest()
    {
        if(!RecvHttpRequestLine() && !RecvHttpRequestHeader()){
            ParseHttpRequestLine();
            ParseHttpRequestHeader();
            RecvHttpRequestBody();
        }

    }

    // 构建响应
    void BuildHttpResponse()
    {
        std::string _path;
        int size = 0; // *这边有疑惑*
        size_t found; // 找后缀

        auto &code = http_response.status_code;
        if (http_request.method != "GET" && http_request.method != "POST")
        {
            // 非法请求
            LOG(Warning, "methos is not right");
            code = BAD_REQUEST;
            goto END;
        }
        // 不是等于get, 就是等于 post
        if (http_request.method == "GET")
        {
            size_t pos = http_request.uri.find("?");
            if (pos != std::string::npos)
            {
                // 有 ？，表示带参
                // 分割 ？ 的左右两边
                Util::CutString(http_request.uri, http_request.path, http_request.query_string, "?");
                // 访问的不是静态网页，使用CGI机制
                http_request.cgi = true;
            }
            else
            {
                // 不带参
                http_request.path = http_request.uri;
            }
        }
        else if (http_request.method == "POST")
        {
            // POST ，使用 CGI 机制
            http_request.cgi = true;
            http_request.path = http_request.uri;
        }
        else
        {
            // method 出错
            // do nothing
        }
        // std::cout << "debug uri: " << http_request.uri << std::endl;
        // std::cout << "debug path: " << http_request.path << std::endl;
        // std::cout << "debug query_string: " << http_request.query_string << std::endl;

        _path = http_request.path;
        http_request.path = WEB_ROOT;
        http_request.path += _path;
        // std::cout << "debug: " << http_request.path << std::endl;

        if (http_request.path[http_request.path.size() - 1] == '/')
        {
            http_request.path += HOME_PAGE;
        }
        // 已经 wwwroot/a/b/c/index.html
        // 判断网页是否存在
        struct stat st;
        if (stat(http_request.path.c_str(), &st) == 0)
        {
            // 说明网页文件是存在的
            if (S_ISDIR(st.st_mode))
            {
                // 说明此时请求的资源是一个目录，是不被允许的，需要做相关处理
                http_request.path += '/';
                http_request.path += HOME_PAGE;
                stat(http_request.path.c_str(), &st);
            }
            // 判断访问的文件是否是可执行文件
            if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH))
            {
                // 特殊处理一下，是可执行, 使用 CGI 机制
                http_request.cgi = true;
            }
            // size = st.st_size; // *yh*
            http_request.size = st.st_size;
        }
        else
        {
            // 说明网页文件是不存在的
            std::string info = http_request.path;
            info += " Not Found! ";
            LOG(Warning, info);
            code = NOT_FOUND;
            goto END;
        }

        // 获取后缀
        found = http_request.path.rfind(".");
        if (found != std::string::npos)
        {
            // 找到 . 了
            http_request.suffix = http_request.path.substr(found);
        }
        else
        {
            http_request.suffix = ".html"; // 默认后缀是 html
        }

        if (http_request.cgi) // CGI 机制开始执行
        {
            code = ProcessCgi();
        }
        else // 主要是访问静态网页
        {
            // 此时静态网页一定是存在的
            // 返回的目的并不是单单的返回静态网页，而是要构建 HTTP 响应
            // code = ProcessNonCgi(size); // 简单的静态网页返回，返回静态网页
            code = ProcessNonCgi(); // 简单的静态网页返回，返回静态网页
        }
    END:
        // if (code != OK)
        // {
        //     // 差错处理
        //     BuildHttpResponseHelper(code);
        // }

        // 优化
        BuildHttpResponseHelper();  // 状态行填充，响应报头也有了，空行也有了，正文有了
        return ;
    }

    // 发送响应
    void SendHttpResponse()
    {
        send(sock, http_response.status_line.c_str(), http_response.status_line.size(), 0);
        for (auto &iter : http_response.response_header)
        {
            send(sock, iter.c_str(), iter.size(), 0);
        }
        send(sock, http_response.blank.c_str(), http_response.blank.size(), 0);

        // 直接从磁盘发送到网卡上
        // sendfile(sock, http_response.fd, nullptr, http_request.size);
        // close(http_response.fd);
        // 
        // fd, response_body
        if(http_request.cgi){
            auto &response_body = http_response.response_body;
            size_t size = 0;
            size_t total = 0;
            const char *start = response_body.c_str();
            while (total < response_body.size() && (size = send(sock, start + total, response_body.size()-total, 0)) > 0)
            {
                total += size;
            }
        }
        else{
            // 静态网页
            sendfile(sock, http_response.fd, nullptr, http_request.size);
            close(http_response.fd);
        }
    }
};

#define DEBUG 1

// class Entrance
class CallBack
{
public:
    CallBack()
    {}
    ~CallBack()
    {}

    void operator()(int sock)
    {
        HandlerRequest(sock);
    }

    void Run(int sock)
    {
        HandlerRequest(sock);
    }

    // http服务器线程执行的函数功能./b  
    // static void *HandlerRequest(void *_sock)
    void HandlerRequest(int sock)
    {
        LOG(Info, "Handler Request Begin....");
        // int sock = *(int *)_sock;
        // delete (int *)_sock;

#ifdef DEBUG
        // for debug
        char buffer[4096];
        recv(sock, buffer, sizeof(buffer), 0);

        std::cout << buffer << std::endl;
#else
        EndPoint *ep = new EndPoint(sock);
        ep->RecvHttpRequest();
        if(!ep->IsStop()){
            LOG(Info, "Recv No Error, Begin Build And Send");
            ep->BuildHttpResponse();
            ep->SendHttpResponse();
        }
        else{
            LOG(Warning, "Recv Error, Stop Build And Send");
        }

        // ep->ParseHttpRequest();
        // ep->BuildHttpResponse();
        // ep->SendHttpResponse();
        delete ep;
#endif

        // std::cout << "get a link: " << sock << std::endl;
        // std::string line;
        // Util::ReadLine(sock, line);
        // std::cout << line << std::endl;

        // close(sock);
        LOG(Info, "Handler Request End....");
        // return nullptr;
    }
};
